/*
 * FacilitatorActor.java
 *
 * Created on April 28, 2005, 11:48 AM
 */

package aa.core;

import java.util.LinkedList;
import aa.core.Platform;
import java.io.Serializable;

/**
 * This class represents a facilitator actor of a cyberorg
 * 
 * @author  xinghuizhao
 */
public class FacilitatorActor extends Actor{
    
    protected transient CyberOrg m_cybHost;
    
    /** Creates a new instance of FacilitatorActor */
    
    
    public FacilitatorActor(CyberOrg p_cybHost){
        
        super();
        
        m_cybHost = p_cybHost;
        
        
    }
    
 
    
    /** Set the host cyberorg <br>
     * it is called after migration, because the new host
     * is created in the new Platform
     */
    public void setHost(){
        Platform currentPlatform = Platform.getPlatform();
        CyberOrg host = currentPlatform.lookupHost(m_athread.getActorName());
        m_cybHost = host;
    }
    
    /**
     * Returns the host cyberorg
     * @return The host cyberorg
     */
    public CyberOrg getHost(){
        return m_cybHost;
    }
    
    /**
     * CyberOrg isolate
     * 
     * @param p_longECash eCash to be allocated to the child
     * @param p_anaActors Actors to be isolated to the child cyberorg
     * @param p_conContract New contract
     * @return The new child cyberorg
     */
    public CyberOrg doIsolate(Long p_longECash, ActorName[] p_anaActors, Contract p_conContract){
        
        return m_cybHost.isolate(p_longECash.longValue(),p_anaActors,p_conContract);
        
    }
    
    /**
     * Remote control isolation (being used in a specific example)
     * 
     * @param p_longECash
     * @param p_anaActors
     * @param p_conContract
     * @return
     */
    public CyberOrg remoteControlIsolate(Long p_longECash,ActorName[] p_anaActors,Contract p_conContract){
        if (m_cybHost == null) setHost();
        ActorName[] newActors = new ActorName[p_anaActors.length];
        LinkedList childActors = m_cybHost.getActors();
        for (int i=0;i<p_anaActors.length;i++){
            int j=0;
            while (!((ActorName)childActors.get(j)).getUAN().equals(p_anaActors[i].getUAN())){
                j++;
            }
            newActors[i] = (ActorName)childActors.get(j);
        }
        return m_cybHost.isolate(p_longECash.longValue(),newActors,p_conContract);
    }
    
    /**
     * CyberOrg assimilate
     * @return The parent cyberorg
     */
    public CyberOrg doAssimilate(){
        
        return m_cybHost.assimilate();
    }
    
    /**
     * Remote control assimilation (being used in a specific example)
     * 
     * @return
     */
    public CyberOrg remoteControlAssimilate(){
        if (m_cybHost == null) setHost();
        return m_cybHost.assimilate();
    }
    
    /**
     * CyberOrg migrate 
     * 
     * @param p_anDestFacilitator The distination facilitator
     * @param p_conNewContract New contranct
     */
    public void doMigrate(ActorName p_anDestFacilitator,Contract p_conNewContract){
        m_cybHost.migrate(p_anDestFacilitator,p_conNewContract);
    }
    
    /**
     *  This method is called in remote migration , when a cyberorg
      is migrating to this facilitator's host
      
     * @param p_conContract The contract which is held by the coming cyberorg
     * @param p_LECash The number of eCash
     * @param p_llActors Actor list of the coming cyberorg
     * @return The facilitator of the coming cyberorg
     */
    public ActorName receiveCyberOrg(Contract p_conContract,Long p_LECash,LinkedList p_llActors){
        CyberOrg migrating = null;
        try{
            migrating = (CyberOrg)call((ActorName)p_llActors.get(0),"getHost");
            System.out.println("migrating....");
            migrating.printInfo();
            
        }catch (Exception e){
            
        }
        
        
        setHost();
        
        m_cybHost.receiveCyberOrg(p_conContract,p_LECash,p_llActors,migrating);
        System.out.println("recived cyberorg: "+System.currentTimeMillis());
        return (ActorName)p_llActors.get(0);
    }
    
    /**
     * Negotiation
     * 
     * @param p_anSender The name of the facilitator which initializes the negotiation
     * @param p_conContract The proposed contract
     * @return A final contract
     */
    
    public Contract negotiate(ActorName p_anSender, Contract p_conContract){
        
        if ((p_conContract.getTicks()<m_cybHost.getTicks())&&(p_conContract.getTicksRate()<m_cybHost.getTicksRate())){
            return p_conContract;
        }
        else{
            return null;
        }
        
    }
    
    /**
     * Try to migrate using proposed contract 
     * 
     * @param p_anReceiver The potential destination
     * @param p_conContract The proposed contract
     */
    public void tryMigrate(ActorName p_anReceiver, Contract p_conContract){
        System.out.println("tryMigrate......"+p_anReceiver+p_conContract);
        Object[] objaAgs = new Object[2];
        objaAgs[0] = m_athread.getActorName();
        objaAgs[1] = p_conContract;
        System.out.println("objaAgs in tryMigrate: "+objaAgs.toString());
        try {
            
            Contract con = (Contract)call(p_anReceiver, "negotiate",m_athread.getActorName(),p_conContract);
        
            if (con != null) doMigrate(p_anReceiver, con);
        }catch(Exception e){
            System.out.println("% tryMigrate:"+e);
        }
        
    }
    
    /*public void accept(ActorName p_anSender,Contract p_conContract){
        send(p_anSender,"success", p_conContract);
    }
    
    public void reject(ActorName p_anSender){
        send(p_anSender,"fail");
    }
    
    public Contract success(Contract p_conContract){
        return p_conContract;
    }
    
    public Contract fail(){
        return null;
    }*/
}
